/**
 * Copyright (c) 2017-present, Facebook, Inc. and its affiliates.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree.
 */
#pragma once

#include <chrono>
#include <folly/small_vector.h>

#include "logdevice/server/RecordRebuildingBase.h"

/**
 * @file RecordRebuildingAmend is a state machine for Amending
 * a single record.
 */

namespace facebook { namespace logdevice {

class CopySetSelector;
struct RebuildingSet;

class RecordRebuildingAmend : public RecordRebuildingBase {
 public:
  /**
   * @param lsn                   LSN of the record
   * @param shard                 Local shard for which this state machine is
   *                              running
   * @param owner                 Object that owns this
   *                              RecordRebuildingAmend object.
   * @param replication           Determine the node set for the epoch
   * @param storeHeader           Header to be used while sending STORE (Amend)
   *                              message
   * @param flags                 LocalLogStoreRecordFormat flags
   * @param newCopyset            New copy set generated by the
   *                              RecordRebuildingStore state machine
   * @param amendRecipientsIndex  Index in newCopyset of nodes requiring Amend
   * @param rebuildingWave        rebuildingWave of RecordRebuildingStore that
   *                              created this state machine
   * @param node_availability     Object to use for checking which
   *                              nodes are alive.
   */
  RecordRebuildingAmend(lsn_t lsn,
                        shard_index_t shard,
                        RecordRebuildingOwner* owner,
                        std::shared_ptr<ReplicationScheme> replication,
                        STORE_Header storeHeader,
                        LocalLogStoreRecordFormat::flags_t flags,
                        copyset_t newCopyset,
                        copyset_t amendRecipients,
                        uint32_t rebuildingWave,
                        const NodeAvailabilityChecker* node_availability =
                            NodeAvailabilityChecker::instance());

  virtual ~RecordRebuildingAmend();

  void start(bool read_only = false) override;

 private:
  void traceEvent(const char* event_type, const char* status) override;
  int curStage_ = 0;
  // Defines whether "amending self" should be in a separate stage. When
  // rebuilding with WAL, remote amends are sent followed by self amend.
  // When rebuilding without WAL, both amends are sent in parallel
  bool useAmendSelfStage_;

 protected:
  folly::small_vector<StageRecipients, 2> stages_;
  void onComplete() override;
  void onRetryTimeout() override;
  void onStoreTimeout() override;
  void onStoreFailed() override;
  void onStageComplete() override;

  friend class TestRecordRebuildingAmend;
};

}} // namespace facebook::logdevice
